#ifndef PW_PBL_DEVICEREGISTER20_HPP
/// 用于定义外设寄存器的模板类
#define PW_PBL_DEVICEREGISTER20_HPP

#if __cplusplus < 202002L
#error "require c++ 20"
#endif

#include <climits>
#include <limits>
#include <type_traits>
#include <utility>

#include "CommonMacro.hpp"

namespace pw_pbl
{
	namespace _deviceregister
	{
		template <typename T, std::size_t BS, std::size_t BN>
		struct bits
		{
			T : BS;
			T value : BN;
		};

		template <typename SRC, typename TGT>
		using CopyConst_t = std::conditional_t<std::is_const_v<std::remove_reference_t<SRC>>, std::add_const_t<TGT>, TGT>;
	}

	/// 外设寄存器模板类
	/// @tparam T 内部数据类型，必须是无符号的，可以是引用，可以CV限定符
	/// @tparam LAYOUT 通常是包含位定义的结构，sizeof(LAYOUT)必须等于sizeof(T)
	/// @note 没有对应的有符号模板，但位域可以作为有符号数返回和设置
	template <typename T, class LAYOUT = void>
	requires(std::is_void_v<LAYOUT>) || (sizeof(LAYOUT) == sizeof(std::decay_t<T>)) struct TDeviceRegister
	{
		using TParm = std::conditional_t<std::is_reference_v<T>, T, std::remove_volatile_t<T>>; /// c++20不允许volatile参数
		using TDecay = std::decay_t<T>;															/// 按值传输时的数据类型

		T value;

		inline constexpr TDeviceRegister(TParm nv = {}) requires(!std::is_reference_v<T>) : value(nv){};

		inline constexpr TDeviceRegister(TParm nv) requires std::is_reference_v<T> : value(nv) {}

		inline void operator=(TDecay nv) requires(!std::is_const_v<std::remove_reference_t<T>>) { this->value = nv; }

		inline operator TDecay() { return this->value; }

		/// 构造一个新的同构常量值
		/// @param nv 新寄存器的值
		inline static constexpr TDeviceRegister<TDecay, LAYOUT> newConst(TDecay nv) { return {nv}; }

		/// 当前对象读取为同构对象——内部数据去掉cv-修饰和引用修饰转换为值类型而布局结构保持不变
		inline constexpr TDeviceRegister<TDecay, LAYOUT> read(void) { return {this->value}; }

		/// 有位定义的结构，返回位结构的引用以便操作位
		inline constexpr decltype(auto) Bits() requires(!std::is_void_v<LAYOUT>) { return (_deviceregister::CopyConst_t<T, LAYOUT> &)this->value; }

		/// 返回指定位域结构的引用
		/// @tparam BS 位域起始位
		/// @tparam BN 位域宽度（位数）
		template <std::size_t BS, std::size_t BN = 1>
		inline constexpr decltype(auto) Bits() { return (_deviceregister::CopyConst_t<T, _deviceregister::bits<TDecay, BS, BN>> &)this->value; }
	};

}

#include "CommonMacro.hpp"

#endif // PW_PBL_DEVICEREGISTER20_HPP
